class PocketCube:
    """
    Pocket Cube Puzzle 的核心任务是实现一个二阶魔方类，并通过一系列测试案例来验证你的实现是否正确。

    1、任务说明
        你需要完成一个模拟二阶魔方的类 `PocketCube`，并实现几个核心方法：

        1.1 构造函数 (`__init__`):
            构建一个初始化的魔方结构。

        1.2 旋转方法 (`rotate`):
            实现魔方的旋转操作。不同的方向和次数会影响魔方的状态。
            魔方可以通过指定方向进行旋转，方向包括前面（Front）、后面（Back）、上面（Up）、下面（Down）、左面（Left）、右面（Right）。
            每个方向可以选择顺时针或逆时针旋转，并可以指定旋转的次数。

        1.3 视角展示方法 (`show_front_up_right_view`):
            返回魔方当前状态的字符图像，显示正面、上面和右面的颜色。
            使用字符图像展示魔方当前状态，输出的格式是固定的，用于表示不同面的颜色。


    2、通过测试用例
        程序提供了一些测试用例，输入一个旋转公式，输出相应的魔方状态字符图像。
        你需要编写代码，使得你的程序在处理这些测试用例时，输出结果与预期的一致。

        2.1 自己测试
            例如，你想测试魔方公式"UR'2UL'2"的执行结果。

            pocketCube = PocketCube() # 实例化你的二阶魔方
            pocketCube.act_formula("UR'2UL'2") # 执行魔方公式
            print(pocketCube.show_front_up_right_view()) # 查看魔方结果

        2.2 使用测试用例测试
            CaseTester类已经为你准备好，它能评估准确率与平均用时。
            使用方法如下：

            CaseTester.test(PocketCube) # 调用CaseTester.test方法，传入PocketCube类即可

    3、注意事项
        3.1 已经定义好的方法不能更改，只能补充方法体的实现。
        3.2 你可以定义额外的类、函数或属性来帮助实现这些功能。


    4、相关资料 - 在线二阶魔方：
        4.1 https://cube-solver.com/#id=2
        4.2 https://www.grubiks.com/puzzles/rubiks-mini-cube-2x2x2/
    """

    def __init__(self):
        """
        这个方法需要你实现。

        通过这个构造方法，构造一个抽象的二阶魔方。
        """

    def rotate(self, direction: str, clockwise=True, times=1) -> None:
        """
        这个方法需要你实现。

        旋转是魔方的唯一交互方式。

        该方法有三个参数
        direction：表示一种旋转方式 需要采用以下的0-5进行标号
        clockwise：顺时针时 为 True；逆时针时 为 False
        times：即旋转次数

        名称      公式符号   direction参数
        Front    F         0
        Back     B         1
        Up       U         2
        Down     D         3
        Left     L         4
        Right    R         5

        魔方旋转公式就是上述公式合在一起（可以参考 https://www.zhihu.com/tardis/bd/art/610770750?source_id=1001 ）

        """

    def show_front_up_right_view(self) -> str:
        """
        这个方法需要你实现。
        用字符展示二阶魔方的 正面-上面-右面 视角
        格式如下:

        魔方一共有六种颜色，用英文首字母表示：
        (W)White
        (R)Red
        (B)Blue
        (G)Green
        (O)Orange
        (Y)Yellow

        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ ▇ A ▇ ▇ ▇               W                     W
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ B ▇ ▇ ▇ C ▇           W       W             W  上面  W
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         D ▇ ▇ E ▇ ▇ F         R     W     B         R     W     B
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ G ▇ H ▇ ▇             R   B             正面 R   B 右面
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         I ▇ ▇ ▇ ▇ ▇ J         R           B         R           B
        ▇ ▇ ▇ ▇ ▇ ▇ ▇         ▇ ▇ K ▇ L ▇ ▇             R   B                 R   B

        假设一个7*6的网格        形成字符位置模板        用颜色首字母填充模板           很简单吧~
        """

        # 为了方便，模板字符串已经给你准备好了
        template = \
            "      {}      \n  {}       {}  \n{}     {}     {}\n    {}   {}    \n{}           {}\n    {}   {}    \n"
        #          A           B        C     D      E      F       G    H       I            J       K    L

        # 模板字符串用 .format 方法进行填充
        filled = template.format(*list("ABCDEFGHIJKL"))

        return filled

    def act_formula(self, formula: str) -> None:
        """
        这个方法已经写好， 不需要你实现。
        这个方法接收一段魔方公式，解析成旋转方式并执行。
        """

        actions = list("FBUDLR")

        cursor = 0
        prev_config = [None, True, 1]

        try:
            while cursor < len(formula):
                char = formula[cursor]

                if char == "'":
                    prev_config[1] = not prev_config[1]

                if char.isdigit():
                    prev_config[2] = int(char)

                if char in actions:
                    if prev_config[0] is not None:
                        self.rotate(*prev_config)

                    prev_config = [actions.index(char), True, 1]

                if cursor == len(formula) - 1:
                    self.rotate(*prev_config)

                cursor += 1
        except:
            raise Exception("公式错误")


class CaseTester:
    """
    这是测试类，在主程序调用 CaseTester.test(放入你完成的二阶魔方类) 即可测试。

    请注意，您的魔方颜色的初始化一定要和测试案例相同，遵循以下规则：

    Front   正面    (R)Red
    Back    背面    (O)Orange
    Up      上面    (W)White
    Down    下面    (Y)Yellow
    Left    左面    (G)Green
    Right   右面    (B)Blue

    """

    TestCases = {
        "case1": {
            "input": "UR'2U'L2",
            "output": "      Y      \n  Y       Y  \nO     W     O\n    R   B    \nB           O\n    G   O    \n"
        },
        "case2": {
            "input": "D2LB'FL'R",
            "output": "      W      \n  O       W  \nG     R     O\n    B   W    \nG           R\n    B   W    \n"
        },
        "case3": {
            "input": "FB2U'F2DU",
            "output": "      B      \n  B       Y  \nY     G     G\n    R   W    \nB           B\n    R   Y    \n"
        },
        "case4": {
            "input": "FB2D'RFD'ULR",
            "output": "      B      \n  B       W  \nR     G     G\n    O   Y    \nY           O\n    B   Y    \n"
        },
        "case5": {
            "input": "D'L'R2FB'U'DF2U'",
            "output": "      R      \n  G       B  \nW     B     W\n    O   W    \nG           G\n    O   W    \n"
        },
        "case6": {
            "input": "D'R2FUF'D'L2FUD",
            "output": "      B      \n  W       W  \nR     W     B\n    O   G    \nY           G\n    W   B    \n"
        },
    }

    @classmethod
    def test(cls, PocketCube: type):

        if not type(PocketCube) == type:
            raise TypeError("类型错误，请放入PocketCube类。")

        import time

        TimeUses = []
        correct_times = 0
        for caseName, body in cls.TestCases.items():

            print(f"测试用例 - {caseName}  -----------------------")

            start_time = time.perf_counter()

            pocketCube = PocketCube()
            pocketCube.act_formula(body['input'])
            yourAns = pocketCube.show_front_up_right_view()

            end_time = time.perf_counter()

            print(f"你的答案\n\n{yourAns}\n")

            if yourAns == body['output']:
                print("正确！！！！")
                correct_times += 1
            else:
                print("错误！！！！")
                print(f"正确答案\n\n{body['output']}\n")

            elapsed_time = end_time - start_time
            TimeUses.append(elapsed_time)

            print(f"用时：{elapsed_time:.6f} 秒\n")

        print(f"{'-' * 80}\n平均用时：{sum(TimeUses) / len(TimeUses):.6f} 秒")
        print(f"正确率：{correct_times / len(cls.TestCases) * 100} %")


if __name__ == '__main__':
    """
    这里是主程序，在主程序通过魔方公式对二阶魔方进行旋转，然后看与测试案例的结果是否相同。
    
    调用 CaseTester.test(放入你完成的二阶魔方类) 即可测试。
    请注意，您的魔方颜色的初始化一定要和测试案例相同，遵循以下规则：

    Front   正面    (R)Red
    Back    背面    (O)Orange
    Up      上面    (W)White
    Down    下面    (Y)Yellow
    Left    左面    (G)Green
    Right   右面    (B)Blue
    
    每个测试用例：
        输入（str）：一段魔方公式
        输出（str）：show_front_up_right_view方法返回的字符串
    """

    # 实例化你的二阶魔方
    pocketCube = PocketCube()

    # 执行一段魔方公式
    pocketCube.act_formula("UR'2UL'2")

    # 查看魔方结果
    print(pocketCube.show_front_up_right_view())

    # 调用测试类进行测试
    # CaseTester.test(PocketCube)
